package algorithm;

import java.io.UnsupportedEncodingException;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import lib.ByteUtil;

public class EncryptDecrypt {

    private static final String encryptErrMsg = "{\"retCode\":\"-2\", \"retMsg\":\"AESFastEncrypt Error!\"}";
    /**
     * 加密函数
     * 
     * @param strEncrypt 需要被加密的字符串
     * @return 被加密之后的字节数组
     */
    public static byte[] AESFastEncrypt(String strEncrypt) { 
        try{
            return AESFastEncrypt(strEncrypt.getBytes("UTF-8"));
        }catch(UnsupportedEncodingException e){ 
            e.printStackTrace();
            return null;
        }
    }
    
    public static byte[] AESFastEncrypt(byte[] content) {
        if (content == null || content.length <= 0)
            return null;

        try {
            return encrypt(content);
            // LogUtil.logD("orignal text:" + strEncrypt);
            // byte[] resultBytes = encrypt(strEncrypt.getBytes("UTF-8"));
            // LogUtil.logD("encrypted text:" + toHex(resultBytes));
        } catch (Exception e) {
            e.printStackTrace();
            try {
                return encrypt(encryptErrMsg.getBytes());
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 解密函数
     * 
     * @param strDecrypt 要被解需密的字节数组
     * @return 被解密之后的字符串
     */
    public static String AESFastDecrypt(byte[] strDecrypt) {
        String result = "AESFastDecrypt Error!";

        if (strDecrypt == null)
            return result;

        try {
            byte[] byteResult = decrypt(strDecrypt);
            result = new String(byteResult, "UTF-8");
            result = result.trim();
        } catch (Exception e) {
            e.printStackTrace();
        } catch (Throwable e) {
            e.printStackTrace();
        }

        return result;
    }
    
    public static byte[] AESFastDecrypt2(byte[] strDecrypt) { 

        if (strDecrypt == null){
            return null;
        } 

        try {
            return  decrypt(strDecrypt);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return encryptErrMsg.getBytes();
    }

    /**
     * 初始化加密/解密 key， 默认使用初始值
     */
    public static void initRawKey(byte[] keys) {
        sKeyBytes = keys.clone();
    }

    /**
     * 初始化加密/解密 IV， 默认使用初始值
     */
    public static void initIvData(byte[] data) {
        sInitVBytes = data.clone();
    }

    /**
     * 下面代码是私有的函数
     */
    private static byte[] sInitVBytes = new byte[] {
            (byte) 0xdf, 0x32, 0x56, (byte) 0xb5,
            (byte) 0x8d, 0x45, (byte) 0x8e, 0x5e,
            0x49, (byte) 0x88, 0x1e, 0x2c,
            0x44, 0x37, (byte) 0x8c, 0x01
    };

    private static byte[] sKeyBytes = new byte[] {
            (byte) 0xa2, (byte) 0xb0, (byte) 0xc0, 0x76,
            (byte) 0xb4, 0x77, 0x54, 0x2d,
            0x67, 0x11, 0x45, 0x3a,
            (byte) 0xc7, 0x6e, 0x1c, (byte) 0xd0
    };

    private static byte[] encrypt(byte[] clearBytes) throws Exception {
        byte[] result = encrypt(getRawKey(), getIVKey(), clearBytes);
        return result;
    }

    private static byte[] decrypt(byte[] encryptedBytes) throws Exception {
        byte[] result = decrypt(getRawKey(), getIVKey(), encryptedBytes);
        return result;
    }

    private static byte[] getRawKey() throws Exception {
        return sKeyBytes;
    }

    private static byte[] getIVKey() throws Exception {
        return sInitVBytes;
    }

    private static byte[] encrypt(byte[] raw, byte[] iv, byte[] clear) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
        byte[] encrypted = cipher.doFinal(clear);
        return encrypted;
    }

    private static byte[] decrypt(byte[] raw, byte[] iv, byte[] encrypted) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
        byte[] decrypted = cipher.doFinal(encrypted);
        return decrypted;
    }

    public static String toHex(String txt) {
        return toHex(txt.getBytes());
    }

    public static String fromHex(String hex) {
        return new String(toByte(hex));
    }

    public static byte[] toByte(String hexString) {
        int len = hexString.length() / 2;
        byte[] result = new byte[len];
        for (int i = 0; i < len; i++)
            result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
        return result;
    }

    public static String toHex(byte[] buf) {
        if (buf == null)
            return "";
        StringBuffer result = new StringBuffer(2 * buf.length);
        for (int i = 0; i < buf.length; i++) {
            appendHex(result, buf[i]);
        }
        return result.toString();
    }

    private final static String HEX = "0123456789ABCDEF";

    private static void appendHex(StringBuffer sb, byte b) {
        sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
    }
    
    public static void main(String[] args) {
        //String str = EncryptDecrypt.AESFastDecrypt("白观超".getBytes());
        String str = "测试";
        byte[] result = EncryptDecrypt.AESFastEncrypt(str);
        System.out.println("encrypt:" + ByteUtil.formatHexStr(result));
        String resultStr = EncryptDecrypt.AESFastDecrypt(result);
        System.out.println(resultStr);
        
        System.out.println("sInitVBytes:" + ByteUtil.formatHexStr(sInitVBytes));
        System.out.println("sKeyBytes:" + ByteUtil.formatHexStr(sKeyBytes));
        
    }
 

}
